﻿#include "qtffmpegcore.h"

#include <QMutex>
#include <QDebug>

QStringList QtFfmpegCore::m_cameraOptions;

QtFfmpegCore::QtFfmpegCore(QObject *parent) : QObject(parent)
{
    static bool isFirst = true;
    static QMutex mutex;

    m_cameraOptions.clear();

    QMutexLocker locker(&mutex);
    if (isFirst) {
        isFirst = false;
        avformat_network_init();
        avdevice_register_all();
        av_log_set_level(AV_LOG_ERROR);
    }

}

QStringList QtFfmpegCore::getCameraNames()
{
    return getDeviceNames(AVMEDIA_TYPE_VIDEO);
}

QStringList QtFfmpegCore::getAudioNames()
{
    return getDeviceNames(AVMEDIA_TYPE_AUDIO);
}

QStringList QtFfmpegCore::getCameraOptions(const QString &name)
{
    QtFfmpegCore::m_cameraOptions.clear();

    av_log_set_callback(QtFfmpegCore::cameraOptionCallback);

    AVFormatContext * ctx = avformat_alloc_context();
    const AVInputFormat * fmt = av_find_input_format(AV_INPUT_FORMAT);
    if (fmt == nullptr){
        av_log_set_callback(av_log_default_callback);

        return QStringList();
    }
    AVDictionary * opt = nullptr;
    av_dict_set(&opt, "list_options", "true", 0);

    avformat_open_input(&ctx, name.toLocal8Bit().data(), fmt, &opt);
    if (opt != nullptr){
        av_dict_free(&opt);
    }
    avformat_close_input(&ctx);
    av_log_set_callback(av_log_default_callback);

    return QtFfmpegCore::m_cameraOptions;
}

void QtFfmpegCore::cameraOptionCallback(void *ptr, int level, const char *fmt, va_list vl)
{
    Q_UNUSED(ptr)
    Q_UNUSED(level)

    static QMutex mutex;
    QMutexLocker locker(&mutex);

    char buf[1024];
    vsprintf(buf, fmt, vl);
    QString line = buf;
    line = line.trimmed();
    line.replace("/r", "");
    line.replace("/n", "");
    line.replace("\"", "");

    if (line.isEmpty()){
        return ;
    }
    //qDebug()<<"out = "<<line;

    static QString option;
    if (line.startsWith("vcodec=") || line.startsWith("pixel_format=")){
        option.clear();
        option.append(line);
    }
    else if (line.startsWith("min s=") && !option.isEmpty())
    {
        QString result = QString("%1 %2").arg(option).arg(line);
        if (!QtFfmpegCore::m_cameraOptions.contains(result)){
            QtFfmpegCore::m_cameraOptions << result;
        }
    }
}

QStringList QtFfmpegCore::getDeviceNames(AVMediaType meidaType)
{
    QStringList deviceNames;

    const AVInputFormat * inFmt = nullptr;
    inFmt = av_find_input_format(AV_INPUT_FORMAT);
    if (inFmt == nullptr){
        av_log(nullptr, AV_LOG_ERROR, "Font input format failed\n");
        return deviceNames;
    }

    AVDeviceInfoList * devList = nullptr;
    avdevice_list_input_sources(inFmt, nullptr, nullptr, &devList);
    if (devList != nullptr){
        //qDebug()<<"device num = "<<QString::number(devList->nb_devices);
        for (int i=0; i<devList->nb_devices; i++){
            AVDeviceInfo * devInfo = devList->devices[i];
            enum AVMediaType type = *devInfo->media_types;
            if (type == meidaType){
                deviceNames.append(devInfo->device_description);
            }
            //qDebug()<<"type = "<<type<<"name = "<<devInfo->device_description;
        }
    }
    avdevice_free_list_devices(&devList);

    return deviceNames;
}

qreal QtFfmpegCore::rationalToDouble(AVRational *rational)
{
    qreal frameRate = (rational->den == 0)? 0 : (qreal(rational->num) / rational->den);
    return frameRate;
}
